# -*- coding: utf-8 -*-

import logging
import traceback

from werkzeug.exceptions import NotFound

import odoo
from odoo.http import request, _request_stack, WebRequest
from odoo import models, tools, http

from ..utils.auth import current_miniapp, current_user
from odoo_contrib.http import JsonRequest, JsonResponse, JSON_METHODS
from odoo_contrib.exceptions import BaseOdooException

logger = logging.getLogger(__name__)


class IrHttp(models.AbstractModel):
    _inherit = 'ir.http'

    @classmethod
    def _auth_method_wechat(cls):
        try:
            current_miniapp._get_current_object()
        except BaseOdooException as e:
            request.auth_exc = e
            raise
        if not request.session.uid:
            request.uid = request.env.ref('wechat.host_user').id
        else:
            request.uid = request.session.uid

    @classmethod
    def _handle_exception(cls, exception):
        if isinstance(exception, BaseOdooException):
            if isinstance(request._get_current_object(), JsonRequest):
                return request._handle_exception(exception)
            else:
                return JsonResponse(exception.data, status=exception.code)
                # return exception.data
        return super()._handle_exception(exception)

    @classmethod
    def _process_form_ids(cls, attr_name):
        miniapp = current_miniapp._get_current_object()

        if attr_name is True:
            attr_name = 'formId'

        req = request.httprequest
        if req.method == 'OPTIONS':
            return

        form_ids = None

        if req.method == 'GET':
            form_ids = request.params.get(attr_name)
            request.params.pop(attr_name, None)
        elif req.method in ('POST', 'PUT', 'DELETE'):
            form_ids = request.params.get(attr_name)
            request.params.pop(attr_name, None)

        if not form_ids:
            return

        # logger.debug('Retrieved form ids form attribute: %s -> %s', attr_name, form_ids)
        
        miniapp.cache_form_ids(current_user.openid, form_ids)

    @classmethod
    def _dispatch(cls):
        # result = super()._dispatch()

        try:
            rule, arguments = cls._find_handler(return_rule=True)
            func = rule.endpoint
        except NotFound as e:
            return cls._handle_exception(e)

        # check authentication level
        try:
            auth_method = cls._authenticate(func.routing["auth"])
        except Exception as e:
            return cls._handle_exception(e)

        processing = cls._postprocess_args(arguments, rule)
        if processing:
            return processing

        # set and execute handler
        try:
            request.set_handler(func, arguments, auth_method)
            result = request.dispatch()
            if isinstance(result, Exception):
                raise result
        except Exception as e:
            return cls._handle_exception(e)

        try:
            formid_attr_name = request.endpoint.routing.get('collect_formids')
        except:
            formid_attr_name = None
        if formid_attr_name:
            try:
                cls._process_form_ids(formid_attr_name)
            except:
                logger.error(
                    'Process form ids from request error: %s',
                    traceback.format_exc(),
                )
        return result

    @classmethod
    def _find_handler(cls, return_rule=False, httprequest=None, registry=None):
        if not httprequest:
            httprequest = request.httprequest
        return cls.routing_map(registry=registry).bind_to_environ(httprequest.environ).match(return_rule=return_rule)

    @classmethod
    def routing_map(cls, registry=None):
        if not registry:
            registry = request.registry
        if not hasattr(cls, '_routing_map'):
            logger.info("Generating routing map")
            installed = registry._init_modules - {'web'}
            if tools.config['test_enable'] and odoo.modules.module.current_test:
                installed.add(odoo.modules.module.current_test)
            mods = [''] + odoo.conf.server_wide_modules + sorted(installed)
            # Note : when routing map is generated, we put it on the class `cls`
            # to make it available for all instance. Since `env` create an new instance
            # of the model, each instance will regenared its own routing map and thus
            # regenerate its EndPoint. The routing map should be static.
            cls._routing_map = http.routing_map(mods, False, converters=cls._get_converters())
        return cls._routing_map
